package com.ruoyi.wms.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.MapstructUtils;
import com.ruoyi.common.mybatis.core.page.PageQuery;
import com.ruoyi.common.mybatis.core.page.TableDataInfo;
import com.ruoyi.wms.domain.bo.WarehouseAreaBo;
import com.ruoyi.wms.domain.entity.WarehouseArea;
import com.ruoyi.wms.domain.vo.WarehouseAreaVo;
import com.ruoyi.wms.mapper.WarehouseAreaMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 库区Service业务层处理
 *
 * @author zcc
 * @date 2024-07-16
 */
@RequiredArgsConstructor
@Service
public class WarehouseAreaService extends ServiceImpl<WarehouseAreaMapper, WarehouseArea> {

    private final WarehouseAreaMapper warehouseAreaMapper;
    private final InventoryService inventoryService;

    /**
     * 查询库区
     */

    public WarehouseAreaVo queryById(Long id) {
        return warehouseAreaMapper.selectVoById(id);
    }

    /**
     * 查询库区列表
     */

    public TableDataInfo<WarehouseAreaVo> queryPageList(WarehouseAreaBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<WarehouseArea> lqw = buildQueryWrapper(bo);
        Page<WarehouseAreaVo> result = warehouseAreaMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询库区列表
     */
    public List<WarehouseAreaVo> queryList(WarehouseAreaBo bo) {
        LambdaQueryWrapper<WarehouseArea> lqw = buildQueryWrapper(bo);
        return warehouseAreaMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<WarehouseArea> buildQueryWrapper(WarehouseAreaBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<WarehouseArea> lqw = Wrappers.lambdaQuery();
        lqw.eq(StrUtil.isNotBlank(bo.getWarehouseId()), WarehouseArea::getWarehouseId, bo.getWarehouseId());
        lqw.eq(StrUtil.isNotBlank(bo.getAreaCode()), WarehouseArea::getAreaCode, bo.getAreaCode());
        lqw.like(StrUtil.isNotBlank(bo.getAreaName()), WarehouseArea::getAreaName, bo.getAreaName());
        lqw.orderByAsc(WarehouseArea::getOrderNum);
        return lqw;
    }

    /**
     * 新增库区
     */

    public void insertByBo(WarehouseAreaBo bo) {
        validateWarehouseAreaNameAndNo(bo);
        WarehouseArea add = MapstructUtils.convert(bo, WarehouseArea.class);
        add.setOrderNum(this.getNextOrderNum());
        warehouseAreaMapper.insert(add);
    }

    private Long getNextOrderNum() {
        LambdaQueryWrapper<WarehouseArea> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(WarehouseArea::getOrderNum);
        wrapper.last("limit 1");
        WarehouseArea warehouseArea = warehouseAreaMapper.selectOne(wrapper);
        return warehouseArea == null ? 0L : warehouseArea.getOrderNum() + 1;
    }

    /**
     * 修改库区
     */

    public void updateByBo(WarehouseAreaBo bo) {
        validateWarehouseAreaNameAndNo(bo);
        WarehouseArea update = MapstructUtils.convert(bo, WarehouseArea.class);
        warehouseAreaMapper.updateById(update);
    }

    private void validateWarehouseAreaNameAndNo(WarehouseAreaBo warehouseArea) {
        LambdaQueryWrapper<WarehouseArea> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(WarehouseArea::getAreaName, warehouseArea.getAreaName()).or().eq(StrUtil.isNotBlank(warehouseArea.getAreaCode()), WarehouseArea::getAreaCode, warehouseArea.getAreaCode());
        List<WarehouseArea> warehouseList = warehouseAreaMapper.selectList(queryWrapper);
        boolean validateNameResult = warehouseList.stream().anyMatch(
            it -> Objects.equals(it.getAreaName(), warehouseArea.getAreaName()) && !Objects.equals(it.getId(), warehouseArea.getId()));
        Assert.isFalse(validateNameResult, "库区名称重复");
        boolean validateNoResult = warehouseList.stream().anyMatch(
            it -> Objects.equals(it.getAreaCode(), warehouseArea.getAreaCode()) && !Objects.equals(it.getId(), warehouseArea.getId()));
        Assert.isFalse(validateNoResult, "库区编号重复");
    }

    /**
     * 删除库区
     */

    public void deleteById(Long id) {
        validIdBeforeDelete(id);
        warehouseAreaMapper.deleteById(id);
    }

    private void validIdBeforeDelete(Long id) {
        if (inventoryService.existsByWarehouseId(id)) {
            throw new ServiceException("删除失败", HttpStatus.CONFLICT, "该库区已有业务关联，无法删除！");
        }
    }

    /**
     * 批量删除库区
     */

    public void deleteByIds(Collection<Long> ids) {
        warehouseAreaMapper.deleteBatchIds(ids);
    }

    @Transactional(rollbackFor = {Exception.class})
    public void updateOrderNum(List<WarehouseAreaBo> tree) {
        if (CollUtil.isEmpty(tree)) {
            return;
        }
        List<WarehouseArea> updateList = MapstructUtils.convert(tree, WarehouseArea.class);
        for (int i = 0; i < updateList.size(); i++) {
            updateList.get(i).setOrderNum((long) i);
        }
        saveOrUpdateBatch(updateList);
    }
}
